"""
参数flags是匹配模式，可以使用按位或’|’表示同时生效，也可以在正则表达式字符串中指定。
Pattern对象是不能直接实例化的，只能通过compile方法得到。匹配模式有：
1).re.I(re.IGNORECASE): 忽略大小写
2).re.M(MULTILINE): 多行模式，改变’^’和’$’的行为
3).re.S(DOTALL): 点任意匹配模式，改变’.’的行为
4).re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
5).re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
6).re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行，忽略空白字符，并可以加入注释
"""
import copy
from base.logcontrol import logger
from re import findall, compile
from base.tools import RegexDict


def __get_value(param, res_json):
    if not param:
        return param
    reg = compile("(.+?)\[(\d+?)\]")
    try:
        _path = param.split(".")
    except Exception:
        logger.error(f"\n\t分割参数异常：{param}\n"
                     f"\tres_json: {res_json}\n")
        raise RuntimeError()
    if len(_path) < 2:
        return param
    _path = _path[1:]
    res = copy.deepcopy(res_json)
    try:
        for elm in _path:
            ind_search = findall(reg, elm)
            if ind_search:
                key, ind = ind_search[0]
                res = res.get(key)[int(ind)]
                continue
            res = res[elm]
    except Exception as e:
        logger.error(f"\n\tjson提取失败：{param},异常:{e}\n"
                     f"\t返回：{res_json}\n")
        raise RuntimeError("json提取失败")
    return res


# "return_$.data.contents[*].id":"name" => {"id1":"name1","id2":"name2"}
def get_object_list_value(reg: dict, resp: dict):
    r = dict()
    path = list()
    key_str, value = reg.popitem()
    sp_list = key_str.split("[*].")
    path.extend(sp_list[0].split(".")[1:])
    key = sp_list[-1]
    contents = copy.deepcopy(resp)
    for _node in path:
        contents = contents.get(_node)
    if not contents:
        return
    for obj in contents:
        r.update({obj.get(key): obj.get(value)})
    return r


# "return_$.data.contents[*list].id":["name","grade"] => {"{id1}":{"name":value,"grade":value}}
def get_content_to_value_dict(reg: dict, resp: dict):
    r = dict()
    content_path = list()
    key_str, value = reg.popitem()
    sp_list = key_str.split("[*list].")
    content_path.extend(sp_list[0].split(".")[1:])
    key = sp_list[-1]
    contents = copy.deepcopy(resp)
    for _node in content_path:
        contents = contents.get(_node)
    if not contents:
        return
    for obj in contents:
        value_dict = dict()
        for _v in value:
            value_dict[_v] = obj.get(_v)
        r.update({obj.get(key): value_dict})
    return r


# return_values : $.data.content[*].[id,name] => {"values":[{"id1":value,"name1":value},{"id2":value,"name2":value}]}
def get_content_object_values(reg: dict, resp: dict):
    content_path = list()
    key_str, value = reg.popitem()
    sp_list = value.split("[*].")
    content_path.extend(sp_list[0].split(".")[1:])
    v_keys = sp_list[-1][1:-1].split(",")
    contents = copy.deepcopy(resp)
    for _node in content_path:
        contents = contents.get(_node)
    if not contents:
        return
    value_list = list()
    for obj in contents:
        temp = dict()
        for k in v_keys:
            temp.update({k: obj.get(k)})
        value_list.append(temp)
    return {key_str: value_list}


# 按规则处理返回
def exec_resp_new(resp, kw, regex="return_"):
    try:
        resp_json = resp.json()
    except Exception as e:
        logger.error(f"\n\t返回数据格式不是json\n"
                     f"\t异常：{e}\n"
                     f"\t接口：{resp.request.__dict__}\n"
                     f"\t返回：{resp.text}\n")
        raise RuntimeError("返回不是json")

    # 检查返回中的success是否为true
    if "ignore" in kw:
        pass
    else:
        if not resp_json.get("success"):
            logger.error(f"\n\t接口返回false\n"
                         f"\t接口：{resp.request.__dict__}\n"
                         f"\t返回：{resp_json}\n")
            raise RuntimeError(f"接口返回success=false:{resp.request.__dict__}")

    _vars = RegexDict(kw, regex).get()

    ret = {}

    if not _vars:
        return resp_json, ret

    for _var in _vars:
        if "cookies" in _var:
            if isinstance(_vars[_var], bool):
                ret.update({_var: resp.cookies.get_dict()})
                continue

        # 在此处新增或修改提取模式
        if "[*]." in _var:
            ret.update(get_object_list_value({_var: _vars[_var]}, resp_json))
            continue
        if "[*list]." in _var:
            ret.update(get_content_to_value_dict({_var: _vars[_var]}, resp_json))
            continue
        if "[*].[" in _vars[_var]:
            ret.update(get_content_object_values({_var: _vars[_var]}, resp_json))
            continue

        _key = __get_value(_var, resp_json)
        if not _key:
            logger.error(f"\n\t提取参数{_var}时返回了空\n")
            raise RuntimeError("提取参数返回空")
        _value = __get_value(_vars.get(_var), resp_json)
        ret.update({_key: _value})
    return resp_json, ret
